

import * as effectTypes from './effectTypes'
// import EventEmitter from 'events';
// let eventEmitter = new EventEmitter();

/**
 * 
 * @param {*} env 
 * @param {*} saga 
 */
export default function runSaga(env,saga){
    let { channel , dispatch } = env;
    // 如果saga是一个生成器函数，执行他就得到迭代器，如果不是，就不需要执行他生成
    let it = typeof saga === 'function'?saga():saga;
    function next(value,isErr){
        let result;
        if(isErr){
            result = it.throw(value)
        }else{
            result = it.next(value)
        }
        let { value:effect,done } = result
        if(!done){
            if(typeof effect[Symbol.iterator] === 'function'){
                runSaga(env,effect) //如果发现产出的是一个迭代器，那就会运行这个迭代器
                next() //运行的时候不会阻塞当前saga，当前saga会继续向下执行
            }else if (effect instanceof Promise) {
                effect.then(next);
            }else{
                switch(effect.type){
                    case effectTypes.TAKE:
                        // 如果effect类型是take，则会暂停当前saga的执行，等待某一个动作的派发，等到之后才会继续向下执行
                        // 等到之后才会继续执行effect
                        // eventEmitter.once(effect.effectTypes,next)
                        channel.once(effect.actionType,next) //只执行一次
                        break;
                    case effectTypes.PUT:
                        // 如果effect的类型是PUT，则需要想仓库派发这个动作
                        dispatch(effect.action)
                        // 派发完毕后继续向下执行saga
                        next()
                        break;
                    case effectTypes.FORK:
                        // 重新开启一个runsaga
                        runSaga(env,effect.saga)
                        // 继续执行next，不会阻塞
                        next()
                        break;
                    case effectTypes.CALL:
                        effect.fn(...effect.args).then(next)
                        break;
                    case effectTypes.CPS:
                        effect.fn(...effect.args,(err,data)=>{
                            if(err){
                                next(err,true)
                            }else{
                                next(data)
                            }
                        })
                    default:
                        break
                }
            }

        }
    }
    next()
}